const express = require('express');
const router = express.Router();
const { exec } = require('child_process');
const util = require('util');
const { verifyAdmin } = require('../middleware/auth');

const execPromise = util.promisify(exec);

/**
 * @route   GET /api/security/firewall/status
 * @desc    获取防火墙状态
 * @access  私有
 */
router.get('/firewall/status', async (req, res) => {
  try {
    // 检查系统使用的防火墙类型（UFW或firewalld）
    let firewallType = null;
    let status = {
      installed: false,
      running: false,
      version: '',
      type: ''
    };

    // 检查UFW
    try {
      await execPromise('which ufw');
      firewallType = 'ufw';
      status.installed = true;
      status.type = 'ufw';
      
      // 获取状态
      const { stdout } = await execPromise('ufw status | grep Status');
      status.running = stdout.includes('active');
      
      // 获取版本
      const versionOutput = await execPromise('ufw version');
      const versionMatch = versionOutput.stdout.match(/ufw\s+(\d+\.\d+)/i);
      status.version = versionMatch ? versionMatch[1] : '';
    } catch (error) {
      // UFW未安装，检查firewalld
      try {
        await execPromise('which firewall-cmd');
        firewallType = 'firewalld';
        status.installed = true;
        status.type = 'firewalld';
        
        // 获取状态
        const { stdout } = await execPromise('firewall-cmd --state');
        status.running = stdout.trim() === 'running';
        
        // 获取版本
        const versionOutput = await execPromise('firewall-cmd --version');
        status.version = versionOutput.stdout.trim();
      } catch (err) {
        // firewalld也未安装
      }
    }
    
    res.json(status);
  } catch (error) {
    res.status(500).json({ error: `获取防火墙状态失败: ${error.message}` });
  }
});

/**
 * @route   POST /api/security/firewall/action
 * @desc    操作防火墙（启动/停止/重载）
 * @access  私有 (仅管理员)
 */
router.post('/firewall/action', verifyAdmin, async (req, res) => {
  try {
    const { action } = req.body;
    
    if (!action) {
      return res.status(400).json({ error: '未指定操作类型' });
    }
    
    // 验证操作类型
    if (!['start', 'stop', 'reload'].includes(action)) {
      return res.status(400).json({ error: '无效的操作类型' });
    }
    
    // 检查系统使用的防火墙类型
    let firewallType = null;
    
    try {
      await execPromise('which ufw');
      firewallType = 'ufw';
    } catch (error) {
      try {
        await execPromise('which firewall-cmd');
        firewallType = 'firewalld';
      } catch (err) {
        return res.status(400).json({ error: '未检测到支持的防火墙' });
      }
    }
    
    // 根据防火墙类型执行相应的命令
    if (firewallType === 'ufw') {
      switch (action) {
        case 'start':
          await execPromise('ufw enable');
          break;
        case 'stop':
          await execPromise('ufw disable');
          break;
        case 'reload':
          await execPromise('ufw reload');
          break;
      }
    } else if (firewallType === 'firewalld') {
      switch (action) {
        case 'start':
          await execPromise('systemctl start firewalld');
          break;
        case 'stop':
          await execPromise('systemctl stop firewalld');
          break;
        case 'reload':
          await execPromise('firewall-cmd --reload');
          break;
      }
    }
    
    res.json({
      message: `防火墙${
        action === 'start' ? '已启动' : 
        action === 'stop' ? '已停止' : 
        '已重载'
      }`
    });
  } catch (error) {
    res.status(500).json({ error: `操作失败: ${error.message}` });
  }
});

/**
 * @route   GET /api/security/firewall/rules
 * @desc    获取防火墙规则
 * @access  私有
 */
router.get('/firewall/rules', async (req, res) => {
  try {
    // 检查系统使用的防火墙类型
    let firewallType = null;
    let rules = [];
    
    try {
      await execPromise('which ufw');
      firewallType = 'ufw';
      
      // 获取UFW规则
      const { stdout } = await execPromise('ufw status numbered');
      
      // 解析输出
      const lines = stdout.split('\n').filter(line => line.match(/^\[\s*\d+\]/));
      
      rules = lines.map(line => {
        const match = line.match(/^\[\s*(\d+)\]\s+(ALLOW|DENY)\s+(\S+)\s+(\S+)\s+(.*)/);
        if (match) {
          return {
            number: match[1],
            action: match[2].toLowerCase(),
            from: match[3],
            to: match[4],
            port: match[5]
          };
        }
        return null;
      }).filter(Boolean);
      
    } catch (error) {
      try {
        await execPromise('which firewall-cmd');
        firewallType = 'firewalld';
        
        // 获取firewalld规则
        const { stdout: zonesOutput } = await execPromise('firewall-cmd --list-all-zones');
        const zones = zonesOutput.split('\n\n').filter(zone => zone.trim());
        
        for (const zoneText of zones) {
          const lines = zoneText.split('\n');
          if (lines.length > 0) {
            const zoneName = lines[0].trim();
            const services = [];
            const ports = [];
            
            for (let i = 1; i < lines.length; i++) {
              const line = lines[i].trim();
              if (line.startsWith('services:')) {
                const serviceList = line.replace('services:', '').trim();
                if (serviceList) {
                  services.push(...serviceList.split(/\s+/));
                }
              } else if (line.startsWith('ports:')) {
                const portList = line.replace('ports:', '').trim();
                if (portList) {
                  ports.push(...portList.split(/\s+/));
                }
              }
            }
            
            // 添加服务规则
            services.forEach(service => {
              rules.push({
                zone: zoneName,
                type: 'service',
                service,
                action: 'allow'
              });
            });
            
            // 添加端口规则
            ports.forEach(port => {
              rules.push({
                zone: zoneName,
                type: 'port',
                port,
                action: 'allow'
              });
            });
          }
        }
      } catch (err) {
        return res.status(400).json({ error: '未检测到支持的防火墙' });
      }
    }
    
    res.json({
      type: firewallType,
      rules
    });
  } catch (error) {
    res.status(500).json({ error: `获取防火墙规则失败: ${error.message}` });
  }
});

/**
 * @route   POST /api/security/firewall/rule
 * @desc    添加防火墙规则
 * @access  私有 (仅管理员)
 */
router.post('/firewall/rule', verifyAdmin, async (req, res) => {
  try {
    const { port, protocol = 'tcp', action = 'allow' } = req.body;
    
    if (!port) {
      return res.status(400).json({ error: '未提供端口' });
    }
    
    // 验证端口
    if (!/^\d+$/.test(port) || parseInt(port) <= 0 || parseInt(port) > 65535) {
      return res.status(400).json({ error: '无效的端口号' });
    }
    
    // 验证协议
    if (!['tcp', 'udp'].includes(protocol)) {
      return res.status(400).json({ error: '无效的协议' });
    }
    
    // 验证操作
    if (!['allow', 'deny'].includes(action)) {
      return res.status(400).json({ error: '无效的操作' });
    }
    
    // 检查系统使用的防火墙类型
    let firewallType = null;
    
    try {
      await execPromise('which ufw');
      firewallType = 'ufw';
      
      // 添加UFW规则
      await execPromise(`ufw ${action} ${port}/${protocol}`);
      
    } catch (error) {
      try {
        await execPromise('which firewall-cmd');
        firewallType = 'firewalld';
        
        // 添加firewalld规则
        const command = action === 'allow' 
          ? `firewall-cmd --permanent --add-port=${port}/${protocol}` 
          : `firewall-cmd --permanent --remove-port=${port}/${protocol}`;
        
        await execPromise(command);
        await execPromise('firewall-cmd --reload');
        
      } catch (err) {
        return res.status(400).json({ error: '未检测到支持的防火墙' });
      }
    }
    
    res.json({
      message: `已${action === 'allow' ? '允许' : '拒绝'}端口 ${port}/${protocol}`
    });
  } catch (error) {
    res.status(500).json({ error: `添加防火墙规则失败: ${error.message}` });
  }
});

/**
 * @route   DELETE /api/security/firewall/rule
 * @desc    删除防火墙规则
 * @access  私有 (仅管理员)
 */
router.delete('/firewall/rule', verifyAdmin, async (req, res) => {
  try {
    const { number } = req.body; // UFW规则编号
    const { port, protocol = 'tcp' } = req.body; // firewalld端口规则
    
    // 检查系统使用的防火墙类型
    let firewallType = null;
    
    try {
      await execPromise('which ufw');
      firewallType = 'ufw';
      
      if (!number) {
        return res.status(400).json({ error: '未提供规则编号' });
      }
      
      // 删除UFW规则
      await execPromise(`yes | ufw delete ${number}`);
      
    } catch (error) {
      try {
        await execPromise('which firewall-cmd');
        firewallType = 'firewalld';
        
        if (!port) {
          return res.status(400).json({ error: '未提供端口' });
        }
        
        // 删除firewalld规则
        await execPromise(`firewall-cmd --permanent --remove-port=${port}/${protocol}`);
        await execPromise('firewall-cmd --reload');
        
      } catch (err) {
        return res.status(400).json({ error: '未检测到支持的防火墙' });
      }
    }
    
    res.json({
      message: `已删除${firewallType === 'ufw' ? '规则 #' + number : `端口 ${port}/${protocol}`}`
    });
  } catch (error) {
    res.status(500).json({ error: `删除防火墙规则失败: ${error.message}` });
  }
});

/**
 * @route   GET /api/security/ports
 * @desc    获取系统开放端口列表
 * @access  私有
 */
router.get('/ports', async (req, res) => {
  try {
    // 使用netstat列出所有监听端口
    const { stdout } = await execPromise('netstat -tuln | grep LISTEN');
    
    // 解析输出
    const ports = stdout.split('\n')
      .filter(Boolean)
      .map(line => {
        const parts = line.trim().split(/\s+/);
        const localAddress = parts[3];
        const [ip, port] = localAddress.split(':');
        
        return {
          protocol: parts[0],
          port: port || localAddress.split('.')?.pop(), // 处理IPv6地址
          ip: ip,
          state: 'LISTENING'
        };
      });
    
    res.json(ports);
  } catch (error) {
    res.status(500).json({ error: `获取开放端口失败: ${error.message}` });
  }
});

/**
 * @route   GET /api/security/ssh/config
 * @desc    获取SSH配置
 * @access  私有 (仅管理员)
 */
router.get('/ssh/config', verifyAdmin, async (req, res) => {
  try {
    // 读取SSH配置文件
    const { stdout } = await execPromise('cat /etc/ssh/sshd_config');
    
    // 解析关键配置
    const config = {
      port: 22,
      permitRootLogin: false,
      passwordAuthentication: false,
      x11Forwarding: false
    };
    
    // 解析端口
    const portMatch = stdout.match(/^Port\s+(\d+)/m);
    if (portMatch) {
      config.port = parseInt(portMatch[1]);
    }
    
    // 解析root登录
    const rootLoginMatch = stdout.match(/^PermitRootLogin\s+(\w+)/m);
    if (rootLoginMatch) {
      config.permitRootLogin = rootLoginMatch[1] === 'yes' || rootLoginMatch[1] === 'Yes';
    }
    
    // 解析密码认证
    const passwordAuthMatch = stdout.match(/^PasswordAuthentication\s+(\w+)/m);
    if (passwordAuthMatch) {
      config.passwordAuthentication = passwordAuthMatch[1] === 'yes' || passwordAuthMatch[1] === 'Yes';
    }
    
    // 解析X11转发
    const x11ForwardingMatch = stdout.match(/^X11Forwarding\s+(\w+)/m);
    if (x11ForwardingMatch) {
      config.x11Forwarding = x11ForwardingMatch[1] === 'yes' || x11ForwardingMatch[1] === 'Yes';
    }
    
    res.json(config);
  } catch (error) {
    res.status(500).json({ error: `获取SSH配置失败: ${error.message}` });
  }
});

/**
 * @route   POST /api/security/ssh/config
 * @desc    更新SSH配置
 * @access  私有 (仅管理员)
 */
router.post('/ssh/config', verifyAdmin, async (req, res) => {
  try {
    const { port, permitRootLogin, passwordAuthentication, x11Forwarding } = req.body;
    
    // 验证配置值
    if (port && (port < 1 || port > 65535)) {
      return res.status(400).json({ error: '无效的端口号' });
    }
    
    // 备份原始配置
    await execPromise('cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak');
    
    // 更新配置文件
    let command = 'cat /etc/ssh/sshd_config';
    
    // 更新端口
    if (port) {
      command += ` | sed 's/^#\\?Port\\s.*/Port ${port}/'`;
    }
    
    // 更新root登录
    if (permitRootLogin !== undefined) {
      command += ` | sed 's/^#\\?PermitRootLogin\\s.*/PermitRootLogin ${permitRootLogin ? 'yes' : 'no'}/'`;
    }
    
    // 更新密码认证
    if (passwordAuthentication !== undefined) {
      command += ` | sed 's/^#\\?PasswordAuthentication\\s.*/PasswordAuthentication ${passwordAuthentication ? 'yes' : 'no'}/'`;
    }
    
    // 更新X11转发
    if (x11Forwarding !== undefined) {
      command += ` | sed 's/^#\\?X11Forwarding\\s.*/X11Forwarding ${x11Forwarding ? 'yes' : 'no'}/'`;
    }
    
    command += ' > /etc/ssh/sshd_config.new && mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config';
    
    // 执行更新
    await execPromise(command);
    
    // 检查配置是否有效
    try {
      await execPromise('sshd -t');
    } catch (error) {
      // 配置无效，恢复备份
      await execPromise('mv /etc/ssh/sshd_config.bak /etc/ssh/sshd_config');
      return res.status(400).json({ error: `SSH配置无效: ${error.message}` });
    }
    
    // 重启SSH服务
    await execPromise('systemctl restart sshd');
    
    res.json({ message: 'SSH配置已更新' });
  } catch (error) {
    // 恢复备份
    try {
      await execPromise('mv /etc/ssh/sshd_config.bak /etc/ssh/sshd_config');
    } catch (e) {
      // 忽略恢复错误
    }
    
    res.status(500).json({ error: `更新SSH配置失败: ${error.message}` });
  }
});

/**
 * @route   GET /api/security/fail2ban/status
 * @desc    获取Fail2ban状态
 * @access  私有
 */
router.get('/fail2ban/status', async (req, res) => {
  try {
    // 检查Fail2ban是否安装
    let installed = false;
    let running = false;
    let version = '';
    let jails = [];
    
    try {
      await execPromise('which fail2ban-client');
      installed = true;
      
      // 检查服务状态
      try {
        const { stdout } = await execPromise('systemctl is-active fail2ban');
        running = stdout.trim() === 'active';
      } catch (error) {
        // 服务可能未运行
      }
      
      // 获取版本
      if (running) {
        const { stdout: versionOutput } = await execPromise('fail2ban-client -V');
        const versionMatch = versionOutput.match(/(\d+\.\d+\.\d+)/);
        version = versionMatch ? versionMatch[1] : '';
        
        // 获取监狱列表
        const { stdout: jailsOutput } = await execPromise('fail2ban-client status');
        const jailsMatch = jailsOutput.match(/Jail list:\s*(.*)/);
        if (jailsMatch && jailsMatch[1]) {
          jails = jailsMatch[1].split(', ').filter(Boolean);
        }
      }
    } catch (error) {
      // Fail2ban未安装
    }
    
    res.json({
      installed,
      running,
      version,
      jails
    });
  } catch (error) {
    res.status(500).json({ error: `获取Fail2ban状态失败: ${error.message}` });
  }
});

/**
 * @route   POST /api/security/fail2ban/action
 * @desc    操作Fail2ban服务（启动/停止/重启）
 * @access  私有 (仅管理员)
 */
router.post('/fail2ban/action', verifyAdmin, async (req, res) => {
  try {
    const { action } = req.body;
    
    if (!action) {
      return res.status(400).json({ error: '未指定操作类型' });
    }
    
    // 验证操作类型
    if (!['start', 'stop', 'restart'].includes(action)) {
      return res.status(400).json({ error: '无效的操作类型' });
    }
    
    // 检查Fail2ban是否安装
    try {
      await execPromise('which fail2ban-client');
    } catch (error) {
      return res.status(400).json({ error: 'Fail2ban未安装' });
    }
    
    // 执行操作
    await execPromise(`systemctl ${action} fail2ban`);
    
    res.json({
      message: `Fail2ban ${
        action === 'start' ? '已启动' : 
        action === 'stop' ? '已停止' : 
        '已重启'
      }`
    });
  } catch (error) {
    res.status(500).json({ error: `操作失败: ${error.message}` });
  }
});

/**
 * @route   GET /api/security/fail2ban/jail/:name
 * @desc    获取指定Fail2ban监狱的状态
 * @access  私有
 */
router.get('/fail2ban/jail/:name', async (req, res) => {
  try {
    const jailName = req.params.name;
    
    // 检查Fail2ban是否安装并运行
    try {
      await execPromise('which fail2ban-client');
      const { stdout } = await execPromise('systemctl is-active fail2ban');
      if (stdout.trim() !== 'active') {
        return res.status(400).json({ error: 'Fail2ban未运行' });
      }
    } catch (error) {
      return res.status(400).json({ error: 'Fail2ban未安装' });
    }
    
    // 获取监狱状态
    const { stdout } = await execPromise(`fail2ban-client status ${jailName}`);
    
    // 解析输出
    const status = {
      name: jailName,
      enabled: stdout.includes('Currently enabled:') && stdout.includes('true'),
      banned: 0,
      filter: '',
      failRegex: [],
      actions: []
    };
    
    // 解析已禁止的IP数量
    const bannedMatch = stdout.match(/Currently banned:\s*(\d+)/);
    if (bannedMatch) {
      status.banned = parseInt(bannedMatch[1]);
    }
    
    // 解析过滤器
    const filterMatch = stdout.match(/Filter:\s*(.*)/);
    if (filterMatch) {
      status.filter = filterMatch[1];
    }
    
    // 解析动作
    const actionsMatch = stdout.match(/Actions:\s*(.*)/);
    if (actionsMatch) {
      status.actions = actionsMatch[1].split(', ').filter(Boolean);
    }
    
    res.json(status);
  } catch (error) {
    res.status(500).json({ error: `获取监狱状态失败: ${error.message}` });
  }
});

/**
 * @route   POST /api/security/fail2ban/unban
 * @desc    解除IP封禁
 * @access  私有 (仅管理员)
 */
router.post('/fail2ban/unban', verifyAdmin, async (req, res) => {
  try {
    const { ip } = req.body;
    
    if (!ip) {
      return res.status(400).json({ error: '未提供IP地址' });
    }
    
    // 验证IP地址格式
    if (!/^(?:\d{1,3}\.){3}\d{1,3}$/.test(ip)) {
      return res.status(400).json({ error: '无效的IP地址格式' });
    }
    
    // 检查Fail2ban是否安装并运行
    try {
      await execPromise('which fail2ban-client');
      const { stdout } = await execPromise('systemctl is-active fail2ban');
      if (stdout.trim() !== 'active') {
        return res.status(400).json({ error: 'Fail2ban未运行' });
      }
    } catch (error) {
      return res.status(400).json({ error: 'Fail2ban未安装' });
    }
    
    // 解除IP封禁
    await execPromise(`fail2ban-client unban ${ip}`);
    
    res.json({ message: `已解除IP ${ip} 的封禁` });
  } catch (error) {
    res.status(500).json({ error: `解除封禁失败: ${error.message}` });
  }
});

module.exports = router; 